/*
 * editorRevoluciones.h
 *
 *  Created on: 07/01/2011
 *      Author: julian
 */

#ifndef EDITORREVOLUCIONES_H_
#define EDITORREVOLUCIONES_H_

#include "coord.h"
#include "mapa.h"
#include <vector>
#include "bscerrada.h"
using namespace std;

class editorRevoluciones {
private:
	vector<Coord>* coordenadas;
	Mapa* terreno;

        struct Comparador {
           Coord ref;
           Comparador(const Coord& ref) : ref(ref) {}

           bool operator()(const Coord& c1, const Coord& c2) {
              return c1.cross(c2)*ref > 0;
           }
        };

        Coord centro(const vector<Coord>& coords) {
           Coord c(0, 0, 0);
           for(size_t i = 0; i < coords.size(); ++i) 
              c += coords[i];

           return c * (1.0/coords.size());
        }

        void ordenar(vector<Coord>& coords) {
           Coord coordCentro = centro(coords);
           Comparador cmp = Comparador(Coord(0,0,1));
           
           for(size_t i = 0; i < coords.size(); ++i) 
              coords[i] += (-1)*coordCentro;

           sort(coords.begin(), coords.end(), cmp);

           for(size_t i = 0; i < coords.size(); ++i) 
              coords[i] += coordCentro;
        }

public:
	editorRevoluciones(Mapa* terreno){
		this->coordenadas = new vector<Coord>;
		this->terreno = terreno;
	}

	void cerrarCurva(){
		if((coordenadas->size()>=3)&&(Bspline::satisfacePrecond(coordenadas->size()))){
                        vector<Coord> v(coordenadas->begin(), coordenadas->end());
                        //
                        //TODO parece que en ciertos casos genera curvas
                        //en "ocho" o en "infinito"
                        //ordenar(v);

			BsplineCerrada* revolucion = new BsplineCerrada(v); 
			this->terreno->agregarRevolucion(revolucion);
			coordenadas->clear();
		}
	}

	/*
	 * Debe recibir coordenadas normalizadas en el intervalo [0;1]x[0;1]x[0;1].
	 * Se descartará el valor de z.
	 */
	void agregarCoordenada(Coord punto){
		Coord nuevoPunto;
		//Desplazamiento por mapa centrado
		float desplX = punto.x();
		float desplY = 1.0 - punto.y();
		float nuevoX = desplX * terreno->ancho();
		float nuevoY = desplY * terreno->alto();
		nuevoPunto.set(nuevoX, nuevoY, 0.0f);
		this->coordenadas->push_back(nuevoPunto);
	}

	void dibujarPuntosControl(){
            glPushAttrib(GL_ALL_ATTRIB_BITS);
		vector<Coord>::iterator it;
		glPointSize(5);
		glBegin(GL_POINTS);
			glColor3f(1.0,0.0,0.0);
			for ( it=coordenadas->begin() ; it != coordenadas->end(); it++ ){
				float coordX = (*it).x()/this->terreno->ancho();
				float coordY = (*it).y()/this->terreno->alto();
				glVertex2f(coordX,coordY);
			}
		glEnd();
            glPopAttrib();
	}

	virtual ~editorRevoluciones(){
		delete coordenadas;
	}
};

#endif /* EDITORREVOLUCIONES_H_ */
